#ifndef ORG_WXW0303_BYTEARRAY_BYTEARRAY_H
#define ORG_WXW0303_BYTEARRAY_BYTEARRAY_H

#include <string.h>
#include <stdarg.h>
#include <errno.h>

#include <stdexcept>
#include <string>
#include "preprocess.h"

namespace std {

template<>
struct char_traits<unsigned char> {
    typedef unsigned char     char_type;
    typedef int               int_type;
    typedef streampos         pos_type;
    typedef streamoff         off_type;
    typedef mbstate_t         state_type;

    static void
    assign(char_type& c1, const char_type& c2) noexcept
    { c1 = c2; }

    static constexpr bool
    eq(const char_type& c1, const char_type& c2) noexcept
    { return c1 == c2; }

    static constexpr bool
    lt(const char_type& c1, const char_type& c2) noexcept
    { return (c1 < c2); }

    static int
    compare(const char_type* s1, const char_type* s2, size_t n)
    { return memcmp(s1, s2, n); }

    static size_t
    length(const char_type* s)
    { return strlen(reinterpret_cast<const char*>(s)); }

    static const char_type*
    find(const char_type* s, size_t n, const char_type& a)
    { return static_cast<const char_type*>(memchr(s, a, n)); }

    static char_type*
    move(char_type* s1, const char_type* s2, size_t n)
    { return static_cast<char_type*>(memmove(s1, s2, n)); }

    static char_type*
    copy(char_type* s1, const char_type* s2, size_t n)
    { return static_cast<char_type*>(memcpy(s1, s2, n)); }

    static char_type*
    assign(char_type* s, size_t n, char_type a)
    { return static_cast<char_type*>(memset(s, a, n)); }

    static constexpr char_type
    to_char_type(const int_type& c) noexcept
    { return static_cast<char_type>(c); }

    static constexpr int_type
    to_int_type(const char_type& c) noexcept
    { return static_cast<int_type>((c)); }

    static constexpr bool
    eq_int_type(const int_type& c1, const int_type& c2) noexcept
    { return c1 == c2; }

    static constexpr int_type
    eof() noexcept
    { return static_cast<int_type>(_GLIBCXX_STDIO_EOF); }

    static constexpr int_type
    not_eof(const int_type& c) noexcept
    { return (c == eof()) ? 0 : c; }
};

}

// 当前实现 std::string 来实现,注意避免调用会使 string 变为 unshareable 的操作.
// 参见 ::std::basic_string.
struct ByteArray {
private:
    typedef std::basic_string<unsigned char>  ucstring;
public:
    class ByteRef;
    friend class ByteRef;

    typedef unsigned char uchar;

    ByteArray() = default;
    ByteArray(const void *ptr,size_t size);
    ByteArray(const char *str);
    ByteArray(size_t size,uchar ch);
    ByteArray(const ByteArray &bytes) = default;
    ByteArray(ByteArray &&bytes);

    ~ByteArray() = default;

    ByteArray& append(const ByteArray & ba);
    ByteArray& append(const char * str);
    ByteArray& append(const void * str, size_t len);
    ByteArray& append(uchar ch);
    ByteArray& appendFormat(const char *f,...) __attribute__((__format__(printf,2,3)));
    ByteArray& appendVFormat(const char *f,va_list ap) __attribute__((__format__(printf,2,0)));
    static ByteArray format(const char *f,...) __attribute__((format(printf,1,2)));
    static ByteArray format();
    static ByteArray vformat(const char *f,va_list ap) __attribute__((format(printf,1,0)));

    uchar at(size_t i) const;
    uchar at_s(size_t i) const;

    size_t capacity() const;
    void reserve(size_t size);
    void clear();

    const char* constData() const;
    char* data();
    const char* data() const;
    // rawData() 返回的结果可能不是以'\0'结尾的.
    const char* constRawData() const;
    char* rawData();
    const char* rawData() const;

    size_t size() const;
    void resize(size_t size);
    bool isEmpty() const;

    void swap(ByteArray &other);

    int compare(const ByteArray &bytes) const;
    int compare(const char *str) const;
    int compare(const void *ptr,size_t size) const;

    bool operator==(const ByteArray &bytes) const;
    bool operator==(const char *str) const;
    bool operator<(const ByteArray &bytes) const;
    bool operator<(const char *str) const;
    bool operator!=(const ByteArray &bytes) const;
    bool operator!=(const char *str) const;
    bool operator<=(const ByteArray &bytes) const;
    bool operator<=(const char *str) const;
    bool operator>(const ByteArray &bytes) const;
    bool operator>(const char *str) const;
    bool operator>=(const ByteArray &bytes) const;
    bool operator>=(const char *str) const;

    ByteArray& operator=(const ByteArray &bytes);
    ByteArray& operator=(ByteArray &&bytes);
    ByteArray& operator=(const char *str);
    ByteArray& operator=(uchar ch);

    ByteArray& operator+=(const ByteArray &bytes);
    ByteArray& operator+=(const char *str);
    ByteArray& operator+=(uchar ch);

    ByteRef operator[](size_t i);
    uchar operator[](size_t i) const;
private:
    void detach();
private:
    ucstring bytes_;
};

/* 1;RawByteArray 与 ByteArray 区别在于:
 * o RawByteArray 内部不会分配空间,只使用用户提供的空间.
 * o RawByteArray 不会保持'\0'结尾.可以调用 isNullTerminated(),setNullterminated()
 *   判断当前是否'\0'结尾,以及设置成'\0'结尾.
 *   * data(),rawData();调用 data() 时,会首先 setNullTerminated() 将当前 RawByteArray
 *     设置为'\0'结尾.而 rawData() 则不会.
 * 2;RawByteArray 与 ByteArray 共有接口保持相同的语义.
 */
struct RawByteArray {
    typedef unsigned char uchar;

    RawByteArray(void *buf,size_t capacity,size_t size = 0);
    RawByteArray(void *buf,size_t capacity,const void *src,size_t size);
    ~RawByteArray() = default;
    RawByteArray& append(const void *src,size_t size);
    RawByteArray& append(const char * str);
    RawByteArray& append(uchar ch);

    RawByteArray& assign(const void *src,size_t size);
    RawByteArray& assign(const char *src);

    uchar at(size_t i) const;
    uchar at_s(size_t i) const;
    uchar back() const;
    uchar back_s() const;
    uchar popBack();
    uchar popBack_s();
    size_t capacity() const;
    void reserve(size_t size);
    void clear();
    const char* constData() const;
    char* data();
    const char* data() const;
    const char* constRawData() const;
    char* rawData();
    const char* rawData() const;
    size_t size() const;
    void resize(size_t size);
    bool isEmpty() const;
    uchar& operator[](size_t i);
    uchar operator[](size_t i) const;

    RawByteArray& operator=(const RawByteArray &bytes);

    // 测试当前 RawByteArray 是否'\0'结尾.即 size_ < capacity_ && [size_] = '\0'.
    bool isNullTerminated() const;
    // 在可以的情况(size_ < capacity_)下,将其设置为'\0'结尾.否则异常.
    void setNullTerminated() const;
private:
    DENY_COPY(RawByteArray);
    DENY_MOVE_COPY(RawByteArray);

    uchar *ptr_ = nullptr;
    size_t capacity_ = 0;
    size_t size_ = 0;
};


/* 将 [src,size) 拷贝到 dst 指向的缓冲区中.
 * o 当 [src,size) 与 [dst,size) 不重叠时,执行 memcpy().
 * o 否则当 src == dst 时,不执行任何操作.
 * o 否则执行 memmove().
 * @return dst;
 */
void* safe_memcpy(void *dst,const void *src,size_t size);
// 可以接受 nullptr.此时将视为空串.
inline size_t safe_strlen(const char *src)
{
    return src == nullptr ? 0 : strlen(src);
}

/* 若 [l,lsize) 以 [r,rsize) 结尾,则返回真. 该函数对空串(下以 NULL 称呼)的处理:
 *    l,lsize           r,rsize        return
 *     NULL              NULL           true
 *     NULL             NOTNUll         false
 *    NOTNULL            NULL           true
 *    NOTNULL           NOTNULL         实际求值.
 */
inline bool endWith(const void *l,size_t lsize,const void *r,size_t rsize)
{
    return lsize >= rsize && (memcmp(static_cast<const char*>(l) + (lsize - rsize),r,rsize) == 0);
}

/* 若 [p1,s1) 以 [p2,s2) 开始,则返回真. 该函数对空串(下以 NULL 称呼)的处理:
 *    p1,s1             p2,s2          return
 *     NULL              NULL           true
 *     NULL             NOTNUll         false
 *    NOTNULL            NULL           true
 *    NOTNULL           NOTNULL         实际求值.
 */
inline bool beginWith(const void *p1,size_t s1,const void *p2,size_t s2)
{
    return s1 >= s2 && (memcmp(p1,p2,s2) == 0);
}

/* lineTraverse() 行遍历,按行遍历 src,size 确定的区间.
 * o f 的调用形式: LineTraverseReturn f(const char *lineBegin,size_t lineSize);
 *   * lineBegin,lineSize;一行内容,不包括'\n',也不一定以'\0'结尾.
 *   * RETURN;表明是否中止遍历.
 */
enum class LineTraverseReturn {
    BREAK = 0,
    CONTINUE
};
template <typename F>
void lineTraverse(const char *src,size_t size,F &&f)
{
    const char * const srcEnd = src + size;
    for (const char *begin = src,*end = src; begin < srcEnd; begin = end) {
        for (end = begin; end < srcEnd && *end != '\n'; ++end)
            /* do nothing */;

        size_t lineSize = end - begin;
        auto traverseRet = f(begin,lineSize);
        if (traverseRet == LineTraverseReturn::BREAK)
            break;

        // 当 lineSize == 0,此时 end 一定不等于 srcEnd.
        if (lineSize == 0)
            ++end;
    }
    return ;
}

template <typename F>
inline void lineTraverse(const char *src,F &&f)
{
    // 完美转发.
    lineTraverse(src,safe_strlen(src),std::forward<F>(f));
}

////////////////////////////RawByteArray Implement Begin////////////////////////
inline RawByteArray& RawByteArray::operator=(const RawByteArray &bytes)
{
    this->assign(bytes.constRawData(),bytes.size());
    return *this;
}

inline auto RawByteArray::popBack() -> uchar
{
    if (isEmpty())
        throw std::runtime_error("ERANGE");
    return popBack_s();
}

inline auto RawByteArray::popBack_s() -> uchar
{
    uchar tmp = back_s();
    --size_;
    return tmp;
}

inline auto RawByteArray::back_s() const -> uchar
{
    return at_s(size() - 1);
}

inline auto RawByteArray::back() const -> uchar
{
    if (isEmpty())
        throw std::runtime_error("ERANGE");
    return back_s();
}

inline RawByteArray& RawByteArray::assign(const void *src,size_t size)
{
    size_ = 0;
    append(src,size);
    return *this;
}

inline RawByteArray& RawByteArray::assign(const char *src)
{
    return assign(src,safe_strlen(src));
}

inline RawByteArray::RawByteArray(void *buf,size_t capacity,size_t size):
    ptr_(static_cast<uchar*>(buf)),
    capacity_(capacity),
    size_(size)
{
    if (size_ > capacity_)
        throw std::runtime_error("ERANGE");
}

inline auto RawByteArray::at(size_t i) const -> uchar
{
    if (i >= size_)
        throw std::runtime_error("ERANGE");
    return at_s(i);
}

inline auto RawByteArray::at_s(size_t i) const -> uchar
{
    return ptr_[i];
}

inline size_t RawByteArray::capacity() const
{
    return capacity_;
}

inline void RawByteArray::reserve(size_t size)
{
    if (size > capacity_)
        throw std::runtime_error("ENOTSUP");
    return ;
}

inline void RawByteArray::clear()
{
    size_ = 0;
}

inline RawByteArray& RawByteArray::append(const char * str)
{
    return append(str,str == nullptr ? 0 : strlen(str));
}

inline RawByteArray& RawByteArray::append(uchar ch)
{
    return append(&ch,1);
}

inline auto RawByteArray::rawData() -> char*
{
    return const_cast<char*>(constRawData());
}

inline auto RawByteArray::constRawData() const -> const char*
{
    return reinterpret_cast<const char*>(ptr_);
}

inline auto RawByteArray::rawData() const -> const char*
{
    return constRawData();
}

inline auto RawByteArray::data() -> char*
{
    return const_cast<char*>(constData());
}

inline auto RawByteArray::constData() const -> const char*
{
    setNullTerminated();
    return reinterpret_cast<const char*>(ptr_);
}

inline auto RawByteArray::data() const -> const char*
{
    return constData();
}

inline size_t RawByteArray::size() const
{
    return size_;
}

inline bool RawByteArray::isEmpty() const
{
    return size_ == 0;
}

inline auto RawByteArray::operator[](size_t i) -> uchar&
{
    return ptr_[i];
}

inline auto RawByteArray::operator[](size_t i) const -> uchar
{
    return at_s(i);
}

inline bool RawByteArray::isNullTerminated() const
{
    return size_ < capacity_ && ptr_[size_] == '\0';
}

inline void RawByteArray::setNullTerminated() const
{
    if (size_ < capacity_)
        ptr_[size_] = '\0';
    else
        throw std::runtime_error("ERANGE");
    return ;
}
////////////////////////////RawPathImplementEnd/////////////////////////////////


typedef ByteArray String;

inline bool operator==(const char *a1, const ByteArray &a2)
{
    return a2.compare(a1) == 0;
}

inline bool operator<(const char *a1, const ByteArray &a2)
{
    return a2.compare(a1) > 0;
}

inline bool operator!=(const char *a1, const ByteArray &a2)
{
    return a2.compare(a1) != 0;
}

inline bool operator<=(const char *a1, const ByteArray &a2)
{
    return a2.compare(a1) >= 0;
}

inline bool operator>=(const char *a1, const ByteArray &a2)
{
    return a2.compare(a1) <= 0;
}

inline bool operator>(const char *a1, const ByteArray &a2)
{
    return a2.compare(a1) < 0;
}

class ByteArray::ByteRef {
    friend class ByteArray;

    ByteArray &a;
    size_t i;

    ByteRef(ByteArray &a,size_t idx);
public:
    ByteRef& operator=(unsigned char c);
    ByteRef& operator=(const ByteRef &b);

    operator unsigned char() const;
    bool operator ==(unsigned char c) const;
    bool operator !=(unsigned char c) const;
    bool operator >(unsigned char c) const;
    bool operator >=(unsigned char c) const;
    bool operator <(unsigned char c) const;
    bool operator <=(unsigned char c) const;
};


#include <stdexcept>

inline ByteArray::ByteArray(const void *ptr,size_t size):
    bytes_(static_cast<const uchar*>(ptr),ptr == nullptr ? 0 : size)
{
}


inline ByteArray ByteArray::vformat(const char *f,va_list ap)
{
    ByteArray tmp;
    tmp.appendVFormat(f,ap);
    return tmp;
}

inline ByteArray::ByteArray(const char *str):
    bytes_()
{
    if (str != nullptr)
        bytes_.assign(reinterpret_cast<const unsigned char*>(str));
    return ;
}

inline ByteArray::ByteArray(size_t size,uchar ch):
    bytes_(size,ch)
{
}

inline ByteArray::ByteArray(ByteArray &&bytes):
    bytes_(std::move(bytes.bytes_))
{
}

// QByteArray::append() 的实现要求,在当前 QByteArray 为空时,不执行拷贝,而是直接赋值,这样
// 当前 QByteArray 与 ba 共享内存.
inline ByteArray& ByteArray::append(const ByteArray &ba)
{
    if (bytes_.empty())
        bytes_ = ba.bytes_;
    else
        bytes_.append(ba.bytes_);
    return *this;
}

inline ByteArray& ByteArray::append(const char * str)
{
    if (str != nullptr && *str != '\0')
        bytes_.append(reinterpret_cast<const unsigned char*>(str));
    return *this;
}

inline ByteArray& ByteArray::append(const void * ptr, size_t size)
{
    if (ptr != nullptr && size != 0)
        bytes_.append(static_cast<const uchar*>(ptr),size);
    return *this;
}

inline ByteArray& ByteArray::append(uchar ch)
{
    bytes_.append(1,(ch));
    return *this;
}

inline auto ByteArray::at(size_t i) const -> uchar
{
    if (i >= size())
        throw std::runtime_error("ByteArray::at(): 参数不合法");
    return at_s(i);
}

inline auto ByteArray::at_s(size_t i) const -> uchar
{
    return reinterpret_cast<const unsigned char*>(constData())[i];
}

inline size_t ByteArray::capacity() const
{
    return bytes_.capacity();
}

inline void ByteArray::reserve(size_t size)
{
    bytes_.reserve(size);
}

inline void ByteArray::clear()
{
    bytes_.clear();
}

inline auto ByteArray::constData() const -> const char*
{
    return reinterpret_cast<const char*>(bytes_.data());
}

inline auto ByteArray::data() -> char*
{
    detach();
    return const_cast<char*>(constData());
}

inline auto ByteArray::data() const -> const char*
{
    return constData();
}

inline const char* ByteArray::constRawData() const
{
    return constData();
}

inline char* ByteArray::rawData()
{
    return data();
}

inline const char* ByteArray::rawData() const
{
    return constRawData();
}

inline void ByteArray::detach()
{
    bytes_.reserve(bytes_.capacity());
    return ;
}

inline size_t ByteArray::size() const
{
    return bytes_.size();
}

inline void ByteArray::resize(size_t size)
{
    bytes_.resize(size);
    return ;
}

inline bool ByteArray::isEmpty() const
{
    return bytes_.empty();
}

inline void ByteArray::swap(ByteArray &other)
{
    bytes_.swap(other.bytes_);
}

inline bool ByteArray::operator==(const ByteArray &bytes) const
{
    return compare(bytes) == 0;
}

inline bool ByteArray::operator==(const char *str) const
{
    return compare(str) == 0;
}

inline int ByteArray::compare(const char *str) const
{
    return compare(str,str == nullptr ? 0 : strlen(str));
}

inline int ByteArray::compare(const ByteArray &bytes) const
{
    return compare(bytes.constData(),bytes.size());
}

inline bool ByteArray::operator<(const ByteArray &bytes) const
{
    return compare(bytes) < 0;
}

inline bool ByteArray::operator<(const char *str) const
{
    return compare(str) < 0;
}

inline bool ByteArray::operator!=(const ByteArray &bytes) const
{
    return !(*this == bytes);
}

inline bool ByteArray::operator!=(const char *str) const
{
    return compare(str) != 0;
}

inline bool ByteArray::operator<=(const ByteArray &bytes) const
{
    return compare(bytes) <= 0;
}

inline bool ByteArray::operator<=(const char *str) const
{
    return compare(str) <= 0;
}

inline bool ByteArray::operator>(const ByteArray &bytes) const
{
    return compare(bytes) > 0;
}

inline bool ByteArray::operator>(const char *str) const
{
    return compare(str) > 0;
}

inline bool ByteArray::operator>=(const ByteArray &bytes) const
{
    return compare(bytes) >= 0;
}

inline bool ByteArray::operator>=(const char *str) const
{
    return compare(str) >= 0;
}

inline ByteArray& ByteArray::operator=(const ByteArray &bytes)
{
    bytes_ = bytes.bytes_;
    return *this;
}

inline ByteArray& ByteArray::operator=(ByteArray &&bytes)
{
    bytes_ = std::move(bytes.bytes_);
    return *this;
}

inline ByteArray& ByteArray::operator=(const char *str)
{
    bytes_.assign(reinterpret_cast<const unsigned char*>(str));
    return *this;
}

inline ByteArray& ByteArray::operator=(uchar ch)
{
    bytes_.assign(1,ch);
    return *this;
}

inline ByteArray& ByteArray::operator+=(const ByteArray &bytes)
{
    return append(bytes);
}

inline ByteArray& ByteArray::operator+=(const char *str)
{
    return append(str);
}

inline ByteArray& ByteArray::operator+=(uchar ch)
{
    return append(ch);
}

inline auto ByteArray::operator[](size_t i) -> ByteRef
{
    return ByteRef(*this,i);
}

inline auto ByteArray::operator[](size_t i) const -> uchar
{
    return at_s(i);
}

inline ByteArray::ByteRef::ByteRef(ByteArray &a1,size_t idx):
    a(a1),i(idx)
{
}

inline auto ByteArray::ByteRef::operator=(unsigned char c) -> ByteRef&
{
    (reinterpret_cast<unsigned char*>(a.data()))[i] = c;
    return *this;
}

inline auto ByteArray::ByteRef::operator=(const ByteRef &b) -> ByteRef&
{
    (reinterpret_cast<unsigned char*>(a.data()))[i] = (reinterpret_cast<const unsigned char*>(b.a.constData()))[b.i];
    return *this;
}

inline ByteArray::ByteRef::operator unsigned char() const
{
    return (reinterpret_cast<const unsigned char*>(a.constData()))[i];
}

inline bool ByteArray::ByteRef::operator ==(unsigned char c) const
{
    return (reinterpret_cast<const unsigned char*>(a.constData()))[i] == c;
}

inline bool ByteArray::ByteRef::operator !=(unsigned char c) const
{
    return (reinterpret_cast<const unsigned char*>(a.constData()))[i] != c;
}

inline bool ByteArray::ByteRef::operator >(unsigned char c) const
{
    return (reinterpret_cast<const unsigned char*>(a.constData()))[i] > c;
}

inline bool ByteArray::ByteRef::operator >=(unsigned char c) const
{
    return (reinterpret_cast<const unsigned char*>(a.constData()))[i] >= c;
}

inline bool ByteArray::ByteRef::operator <(unsigned char c) const
{
    return (reinterpret_cast<const unsigned char*>(a.constData()))[i] < c;
}

inline bool ByteArray::ByteRef::operator <=(unsigned char c) const
{
    return (reinterpret_cast<const unsigned char*>(a.constData()))[i] <= c;
}

inline ByteArray ByteArray::format()
{
    return ByteArray{};
}

// 若 [ptr1,ptr1 + size1) 与 [ptr2,ptr2 + size2) 不重叠,则返回真.
inline bool
not_overlap(const void *ptr1,size_t size1,const void *ptr2,size_t size2)
{
#if 0
    if (ptr1 == nullptr)
        size1 = 0;
    if (ptr2 == nullptr)
        size2 = 0;
#endif
    const char *p1 = static_cast<const char*>(ptr1);
    const char *p2 = static_cast<const char*>(ptr2);
    return !((p1 + size1) > p2 && p1 < (p2 + size2));
}



















#endif // ORG_WXW0303_BYTEARRAY_BYTEARRAY_H


